package com.btl.component.log.mark;

import com.btl.boot.core.util.JsonUtils;
import com.btl.boot.exception.BizException;
import com.btl.boot.exception.SysException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;

/**
 * @author :  Frank Zhang
 * @version :  1.0
 * @Description :  Catching and Logging
 * @CreateDate :  2020/11/09
 */
@Aspect
@Slf4j
@Order(1)
public class LogMarkAspect {

    /**
     * <a href="https://blog.csdn.net/zhengchao1991/article/details/53391244">The syntax of pointcut </a>
     */
    @Pointcut("(@within(com.btl.component.log.mark.LogMark) && execution(public * *(..))||@annotation(com.btl.component.log.mark.LogMark))")
    public void pointcut() {
    }

    @Around(value = "pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        long startTime = System.currentTimeMillis();
        logRequest(joinPoint);
        Object response = null;
        try {
            response = joinPoint.proceed();
        } catch (Throwable e) {
            handleException(joinPoint, e);
        } finally {
            logResponse(startTime, response);
        }
        return response;
    }

    private void handleException(ProceedingJoinPoint joinPoint, Throwable e) {
        if (e instanceof BizException) {
            log.warn("BIZ EXCEPTION : {}", e.getMessage());
            // 在Debug的时候，对于BizException也打印堆栈
            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }
            throw (BizException) e;
        }
        log.error("SYS EXCEPTION: {}", e.getMessage(), e);
        throw new SysException(e.getMessage(), e);
    }


    private void logResponse(long startTime, Object response) {
        try {
            long endTime = System.currentTimeMillis();
            if (log.isInfoEnabled()) {
                log.info("RESPONSE: {}", JsonUtils.toJsonString(response));
                log.info("COST: {}ms", (endTime - startTime));
            }
        } catch (Exception e) {
            //swallow it
            log.error("Response error: {}", e.getMessage(), e);
        }
    }

    private void logRequest(ProceedingJoinPoint joinPoint) {
        if (!log.isInfoEnabled()) {
            return;
        }
        try {
            log.info("START PROCESSING: {}", joinPoint.getSignature().toShortString());
            Object[] args = joinPoint.getArgs();
            for (Object arg : args) {
                String requestJson = JsonUtils.toJsonString(arg);
                log.info("REQUEST: {}", requestJson);
            }
        } catch (Exception e) {
            //swallow it
            log.error("Request error: {}", e.getMessage(), e);
        }
    }

}
